#pragma once
#include "../comm/Log.h"
#include "../comm/util.h"
#include "../comm/msg.pb.h"
#include <unordered_map>
#include <memory>
#include <mutex>

namespace ns_queue
{
    using namespace ns_log;
    using namespace ns_util;
    using namespace ns_proto;

    // 队列数据描述
    struct Queue
    {
        using ptr = shared_ptr<Queue>;

        string _name;                                          // 名称
        bool _IsDurable;                                       // 队列持久化标志
        bool _exclusive;                                       // 是否独占标志
        bool _auto_delete;                                     // 自动删除标志
        google::protobuf::Map<std::string, std::string> _args; // 其它参数

        Queue() {}

        Queue(const string &name, const bool &IsDurable, const bool &exclusive,
              const bool &auto_delete,
              const google::protobuf::Map<std::string, std::string> &args)
            : _name(name), _IsDurable(IsDurable), _exclusive(exclusive),
              _auto_delete(auto_delete), _args(args)
        {
        }

        // 将数据库格式(key=val&key=val.....)的字符串解析到unordered_map里
        void set_args(const string &args)
        {
            int begin = 0, end = 0;
            while (begin < args.size())
            {
                end = args.find('=', begin);
                string key = args.substr(begin, end - begin);
                begin = end + 1;

                end = args.find('&', begin);
                string val = args.substr(begin, end - begin);
                begin = end + 1;

                _args[key] = val; // 数据存储

                if (end == string::npos)
                    break;
            }
        }
        // 将unordered_map里的数据取出来组织成数据库格式
        string get_args()
        {
            if (_args.empty())
                return "";
            string args;
            for (const auto &p : _args)
            {
                args += p.first;
                args += '=';
                args += p.second;
                args += '&';
            }
            args.pop_back();
            return args;
        }
    };

    // 队列持久化管理(将队列数据存储到数据库中)
    class QueueDurable
    {
    public:
        QueueDurable(const string &dbfile)
            : _sql_helper(dbfile)
        {
            // 如果给的是一个路径且父级路径不存在时
            string path = FileOper::parentdir(dbfile);
            FileOper::createdir(path);
            assert(_sql_helper.open());

            // 创建表
            create_table();
        }

        // 创建、删除队列数据表
        void create_table()
        {
            string CREATE_TABLE = "create table if not exists queue_table(\
            name varchar(32) primary key, durable int, exclusive int, \
            auto_delete int, args varchar(64));";
            bool ret = _sql_helper.exec(CREATE_TABLE, nullptr, nullptr);
            if (!ret)
            {
                LOG(WARNING) << "创建队列数据表失败" << endl;
                abort(); // 异常退出
            }
        }
        void delete_table()
        {
            string DROP_TABLE = "drop table if exists queue_table;";
            bool ret = _sql_helper.exec(DROP_TABLE, nullptr, nullptr);
            if (!ret)
            {
                LOG(WARNING) << "删除队列数据表失败" << endl;
                abort(); // 异常退出
            }
        }

        // 增加、删除指定队列
        void insert_queue(const Queue::ptr &que)
        {
            string INSERT_SQL = "insert into queue_table values('%s', %d, %d, %d, '%s');";
            char buffer[1024] = {0};
            string args = que->get_args();
            sprintf(buffer, INSERT_SQL.c_str(), que->_name.c_str(), que->_IsDurable,
                    que->_exclusive, que->_auto_delete, args.c_str());
            bool ret = _sql_helper.exec(buffer, nullptr, nullptr);
            if (!ret)
            {
                LOG(WARNING) << "增加指定队列失败" << endl;
                return;
            }
        }
        void delete_queue(const string &name)
        {
            // string DELETE_SQL = "delete from queue_table where name='%s';";
            stringstream ss;
            ss << "delete from queue_table where name=";
            ss << "'" << name << "';";
            bool ret = _sql_helper.exec(ss.str(), nullptr, nullptr);
            if (!ret)
            {
                LOG(WARNING) << "删除指定队列失败" << endl;
                return;
            }
        }

        // 查询(恢复)所有的队列数据
        unordered_map<string, Queue::ptr> recovery_all() // second类型采用指针提高管理
        {
            unordered_map<string, Queue::ptr> ret;
            string SQL = "select * from queue_table;";
            _sql_helper.exec(SQL, recovery, &ret);

            return ret;
        }

    private:
        static int recovery(void *args, int col, char **row_data, char **field_name)
        {
            // 传来的容器参数进行强转
            using queue_map = unordered_map<string, Queue::ptr>;
            queue_map *ret = static_cast<queue_map *>(args);

            // 创建队列对象指针
            shared_ptr<Queue> exp = make_shared<Queue>();

            // 队列数据填充
            exp->_name = row_data[0];
            exp->_IsDurable = static_cast<bool>(atoi(row_data[1]));
            exp->_exclusive = static_cast<bool>(atoi(row_data[2]));
            exp->_auto_delete = static_cast<bool>(atoi(row_data[3]));
            if (row_data[4]) // 判断数据是否存在
                exp->set_args(row_data[4]);

            ret->insert(make_pair(exp->_name, exp)); // 插入数据

            return SQLITE_OK;
        }

    private:
        SqliteHelper _sql_helper; // 数据库句柄
    };

    //----------------------------------------------------------------------------
    // 队列管理方法(对外提供)
    class QueueManage
    {
    public:
        QueueManage(const string &dbfile)
            : _queue_durable(dbfile)
        {
            // 构造的时候就进行数据恢复
            _queues = _queue_durable.recovery_all();
        }

        // 声明(创建)一个队列
        void declare_queue(const string &name,
                           const bool &IsDurable,
                           const bool &exclusive,
                           const bool &auto_delete,
                           const google::protobuf::Map<std::string, std::string> &args)
        {
            unique_lock<mutex> lock(_mtx);
            if (_queues.count(name))
            {
                LOG(WARNING) << "该队列名称已经存在" << endl;
                return;
            }
            auto exp = make_shared<Queue>(name, IsDurable, exclusive, auto_delete, args);
            if (IsDurable == true)
            {
                _queue_durable.insert_queue(exp);
            }
            _queues.insert(make_pair(name, exp));
        }

        // 删除指定队列
        void delete_queue(const string &name)
        {
            unique_lock<mutex> lock(_mtx);
            if (!_queues.count(name))
            {
                LOG(WARNING) << "该队列不存在" << endl;
                return;
            }
            if (_queues[name]->_IsDurable) // 判断库中是否存有该队列数据
                _queue_durable.delete_queue(name);
            _queues.erase(name);
        }

        // 获取指定队列数据
        Queue::ptr select_queue(const string &name)
        {
            unique_lock<mutex> lock(_mtx);
            if (!_queues.count(name))
            {
                LOG(WARNING) << "该队列不存在" << endl;
                return Queue::ptr();
            }
            return _queues[name];
        }

        // 获取所有的队列信息
        unordered_map<string, Queue::ptr> get_all()
        {
            unique_lock<mutex> lock(_mtx);
            if (_queues.empty())
            {
                LOG(WARNING) << "当前不存在任何队列" << endl;
            }
            return _queues;
        }

        //----------------------------------------以下用于测试
        // 判断队列是否存在(供测试使用)
        bool exist(const string &name)
        {
            unique_lock<mutex> lock(_mtx);
            return _queues.count(name);
        }

        // 清除队列(供测试使用)
        void clear()
        {
            unique_lock<mutex> lock(_mtx);
            _queues.clear();
            _queue_durable.delete_table();
        }

        // 队列数量(供测试使用)
        size_t size()
        {
            unique_lock<mutex> lock(_mtx);
            return _queues.size();
        }

    private:
        QueueDurable _queue_durable;               // 队列持久化处理
        unordered_map<string, Queue::ptr> _queues; // 存储所有队列
        mutex _mtx;                                // 防止多线程同时执行
    };

}